﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xplang.run;
using xplang.abstractions;
using xplang.contexts;

namespace xplang.parse
{
  public abstract class CompilerForImplementatedCode : Compiler
  {
    public CompilerForImplementatedCode(ClassDecl declaringClass, Compiler parentCompiler, ImplementationCode code)
    {
      this.parentCompiler = parentCompiler;
      if (parentCompiler != null)
        current = parentCompiler.current;
      this.code = code;
      this.declaringClass = declaringClass;
    }

    public readonly ClassDecl declaringClass;
    public abstract OpCode CompileImplementatedCode(ImplementationCode code);
    public readonly ImplementationCode code;
    protected int tokenIndex;
    private Token last;
    public readonly Compiler parentCompiler;

    public override void nextToken()
    {
      if (parentCompiler == null)
      {
        if (tokenIndex >= code.tokens.Count)
        {
          if (last == null)
            return;
          current = new Token(last.sourceCode, last.start, last.length, last.prec, TokenType.ttEOF, last.text);
        }
        else
        {
          current = code.tokens[tokenIndex];
          last = current;
          tokenIndex++;
        }
      }
      else
      {
        parentCompiler.nextToken();
        current = parentCompiler.current;
      }
    }
  }

  public delegate CompilerForImplementatedCode GetCompilerForImplementatedCode(ImplementationCode implementationCode);
  public delegate void ImplementatedCode(ImplementationCode implementationCode);

  public class ImplementationCode
  {

    public event GetCompilerForImplementatedCode getCompiler;
    public event ImplementatedCode implementatedCode;
    public List<Token> tokens;
    public OpCode code;

    public void compile()
    {
      CompilerForImplementatedCode comp = getCompiler(this);
      if (comp.parentCompiler == null)
        comp.nextToken();
      code = comp.CompileImplementatedCode(this);
      implementatedCode(this);
    }
  }

}
